package com.hhuhh.smarthome.utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;

import org.apache.mina.util.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

/**
 * RSA公钥/密钥生成工具
 * @author John zhang
 * @version 0.1
 */
public class RSAHelper {
	
	/**
	 * 十六进制字符集
	 */
	private static char[] HEXCHAR = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
	/**
	 * rsa加密位数
	 */
	private static int KEY_LENGTH = 1024;
	/**
     * rsa最大加密密文大小
     */
	private static int MAX_ENCRYPT_BLOCK = 128;
	/**
     * rsa最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;
    
    /**
     * 生成密钥(包含公钥/私钥)持有者并返回
     * @return
     * @throws NoSuchAlgorithmException
     */
	public static KeyPair generateKey() throws NoSuchAlgorithmException {
		KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider());
		kpGen.initialize ( KEY_LENGTH, new SecureRandom () );

		KeyPair keyPair = kpGen.generateKeyPair ();
        
		System.out.println ( new String( new Base64().encode ( keyPair.getPublic ().getEncoded ()) ) );
		
		return keyPair;
        /*PEMParser pemRd;
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        PEMWriter             pWrt = new PEMWriter(new OutputStreamWriter(bOut));
        
        KeyPair kPair = null;
        try {
			pWrt.writeObject(keyPair.getPublic());
			pWrt.close();

	        pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
	        
	        // SubjectPublicKeyInfo pub = SubjectPublicKeyInfo.getInstance(pemRd.readObject());
	        JcaPEMKeyConverter   converter = new JcaPEMKeyConverter().setProvider( new BouncyCastleProvider() );

	        // PublicKey k = converter.getPublicKey(pub);

	        bOut = new ByteArrayOutputStream();
	        pWrt = new PEMWriter(new OutputStreamWriter(bOut));
	        
	        pWrt.writeObject(keyPair.getPrivate());
	        
	        pWrt.close();
	        
	        pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray())));
	        
	        kPair = converter.getKeyPair((PEMKeyPair)pemRd.readObject());
	        System.out.println ( new String( new Base64().encode ( kPair.getPublic ().getEncoded ()) ) );
		} catch ( IOException e ) {
			e.printStackTrace();
		}
        return kPair;*/
	}

	/**
	 * 利用公钥将数据进行RSA加密并返回
	 * @return byte[]
	 */
	public static byte[] encrypt( RSAPublicKey publicKey, byte[] data ) {
		if ( publicKey != null ) {
			ByteArrayOutputStream out = null;
			try {
				Cipher cipher = Cipher.getInstance ( "RSA", new BouncyCastleProvider() );
				cipher.init ( Cipher.ENCRYPT_MODE, publicKey );
				out = new ByteArrayOutputStream ();
				int length = data.length;
				byte[] buf = new byte[ MAX_ENCRYPT_BLOCK ];
				// 对数据分段加密
				for( int i = 0, offset = 0; ( offset = i * MAX_ENCRYPT_BLOCK ) < length; i++ ) {
					if( length > MAX_ENCRYPT_BLOCK + offset ) {
						buf = cipher.doFinal ( data, offset, MAX_ENCRYPT_BLOCK );
					} else {
						buf = cipher.doFinal ( data, offset, length - offset );
					}
					out.write ( buf, 0, buf.length );
				}
				return out.toByteArray ();
			} catch ( Exception e ) {
				e.printStackTrace ();
			} finally {
				try {
					if ( out != null ) out.close ();
				} catch ( IOException e ) {
					e.printStackTrace ();
				}
			}
		}
		return null;
	}

	/**
	 * 利用私钥将加密后的数据进行解密
	 * @return byte[]
	 */
	public static byte[] decrypt( RSAPrivateKey privateKey, byte[] data ) {
		if ( privateKey != null ) {
			ByteArrayOutputStream out = null;
			try {
				Cipher cipher = Cipher.getInstance ( "RSA", new BouncyCastleProvider() );
				cipher.init ( Cipher.DECRYPT_MODE, privateKey );
				out = new ByteArrayOutputStream ();
				int length = data.length;
				byte[] buf = new byte[ MAX_DECRYPT_BLOCK ];
				// 对数据分段解密
				for( int i = 0, offset = 0; ( offset = i * MAX_DECRYPT_BLOCK ) < length; i++ ) {
					if( length > MAX_DECRYPT_BLOCK + offset ) {
						buf = cipher.doFinal ( data, offset, MAX_DECRYPT_BLOCK );
					} else {
						buf = cipher.doFinal ( data, offset, length - offset );
					}
					out.write ( buf, 0, buf.length );
				}
				return out.toByteArray ();
			} catch ( Exception e ) {
				e.printStackTrace ();
			} finally {
				try {
					if ( out != null ) out.close ();
				} catch ( IOException e ) {
					e.printStackTrace ();
				}
			}
		}
		return null;
	}
	
	/**
	 * 对公钥解码,并返回RSA公钥
	 * @param publicKeyEncoded rsa公钥编码
	 * @return
	 */
	public static RSAPublicKey decodePublicKey( byte[] publicKeyEncoded ) {
		if( publicKeyEncoded == null ) {
			throw new IllegalArgumentException ( "publicKeyEncoded must can not be null!" );
		}
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec( publicKeyEncoded );
		try {
			KeyFactory keyFactory = KeyFactory.getInstance( "RSA", new BouncyCastleProvider() );
			RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic( keySpec );
			return publicKey;
		} catch ( Exception e ) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 将二进制转换为十六进制字符串
	 * @param b
	 * @return
	 */
	public static String toHexString( byte[] b ) {
		if( b == null ) {
			throw new IllegalArgumentException ( "b must can not be null!" );
		}
		StringBuilder sb = new StringBuilder ( b.length * 2 );
		for ( int i = 0; i < b.length; i++ ) {
			sb.append ( HEXCHAR[( b[i] & 0xf0 ) >>> 4] );
			sb.append ( HEXCHAR[b[i] & 0x0f] );
		}
		return sb.toString ();
	}

}